home *** CD-ROM | disk | FTP | other *** search
/ Ian & Stuart's Australian Mac 1 / Ian and Stuart's One (Australia).iso / Australasian Legends / Commercial / Rainbow Hill / MacDOS™ 2.0.0 / filters / filter projects / speakOut.c < prev    next >
C/C++ Source or Header  |  1994-06-13  |  7KB  |  227 lines

  1. //    speakOut.c    uses the Speech Manager to speak out the messages.
  2. //
  3. //    94/06/12    File created
  4. //    94/06/13    First version completed
  5. //
  6. //--------------------------------------------------------------------------------------------------
  7. //    Copyright © 1994 by Rainbow Hill Pty Ltd.
  8. //
  9. //    This program is free software; you can redistribute it and/or modify it under the terms of
  10. //    the GNU General Public License as published by the Free Software Foundation; either version 2
  11. //    of the License, or any later version.
  12. //
  13. //    This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
  14. //    without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  15. //    See the GNU General Public License for more details.
  16. //
  17. //    You should have received a copy of the GNU General Public License along with this program;
  18. //    if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19. //
  20.  
  21. #include <Errors.h>
  22. #include <Events.h>
  23. #include <Speech.h>
  24. #include <GestaltEqu.h>
  25. #include "pipe.h"
  26.  
  27. static SpeechChannel    chan;
  28.  
  29. static pipeParmsFun_t    HandleParameters;
  30.  
  31. main() {
  32.     OSErr                os_err;
  33.     unsigned char        buff[pipeSize];
  34.     EventRecord            keyboardPollEvent;
  35.  
  36.     // Mac Toolbox initialisation
  37.     MaxApplZone();
  38.     InitGraf(&thePort);
  39.     InitWindows();
  40.     InitDialogs(0L);
  41.     InitCursor();
  42.  
  43.     // initialise the incoming pipe
  44.     PipeInit(HandleParameters);
  45.  
  46.     // keep getting records from the master as long as no error occurs
  47.     while (true) {
  48.  
  49.         // wait to receive the next record
  50.         PipePoll(buff);
  51.  
  52.         // speak up
  53.         os_err = SpeakText(chan, (Ptr)&buff[1], (long)buff[0]);
  54.         if (os_err != noErr) PipeReportError(os_err, nil);
  55.         while (SpeechBusy() > 0) {
  56.             if (
  57.                     WaitNextEvent(keyDownMask, &keyboardPollEvent, 0L, nil)
  58.                     &&
  59.                     PipeIsBreak_M(keyboardPollEvent)
  60.                 )
  61.                 PipeReportError(userCanceledErr, nil);
  62.             }
  63.  
  64.         // keep MacDOS happy by sending an empty message
  65.         *buff = '\0';
  66.         PipeSendData(buff);
  67.         }
  68.     } // main
  69.  
  70. //--------------------------------------------------------------------------------- HandleParameters
  71. static OSErr HandleParameters(unsigned char *p) {
  72.     typedef enum {
  73.         idleState,        // between parameters
  74.         slashState,        // slash found
  75.         optionState,    // option found
  76.         numState        // assembling a number
  77.         } state_t;
  78.  
  79.     short            k;
  80.     state_t            s;
  81.     char            opt;
  82.     unsigned char    aNum[8];        // 7 characters are plenty!
  83.     long            aLong;
  84.     OSErr            err;
  85.     short            voiceCount;
  86.     VoiceSpec        voice;
  87.     Fixed            pitch;
  88.     Fixed            rate;
  89.     short            voiceID;
  90.     short            pitchIncr;
  91.     short            speed;
  92.     long            result;
  93.  
  94.     // check that we have speech
  95.     err = Gestalt(gestaltSpeechAttr, &result);
  96.     if (err != noErr || (result & (1 << gestaltSpeechMgrPresent)) == 0)
  97.         PipeReportError(pipeFilteringErr, "\pSpeech Manager not available");
  98.  
  99.     //
  100.     //    Three parameters are supported:
  101.     //      /P to increment or decrement the voice pitch (default: 0)
  102.     //      /S to set the speed of the speech in words per minute (default: use system default)
  103.     //      /V use a voice ID (default: use system default)
  104.     //
  105.     //    In any case, the format is /Xy, where 'y' is an integer number, possibly including a
  106.     //    plus or minus unary sign.
  107.     //
  108.     //    The parameters come in any order, in upper or lower case, and separated by single
  109.     //    spaces.
  110.     //
  111.  
  112.     // add a space at the end to simplify the analysis (there should be space available!)
  113.     p[0]++;
  114.     p[p[0]] = '\0';
  115.  
  116.     // initialise the speech parameters
  117.     voiceID = 0;
  118.     pitchIncr = 0;
  119.     speed = 0;
  120.  
  121.     // scan the parameter list to update the speech parameters if necessary
  122.     s = idleState;
  123.     for (k = 1; k <= p[0]; k++) {
  124.         switch (s) {
  125.  
  126.             case idleState:
  127.                 if (p[k] != '\0') {
  128.                     if (p[k] != '/')
  129.                         PipeReportError(pipeFilteringErr, "\pAll parameters must begin with a slash");
  130.                     s = slashState;
  131.                     }
  132.                 break;
  133.  
  134.             case slashState:
  135.                 opt = p[k];
  136.                 if (opt >= 'a' && opt <= 'z') opt -= 'a' - 'A';
  137.                 if (opt != 'P' && opt != 'S' && opt != 'V')
  138.                     PipeReportError(pipeFilteringErr, "\pOnly options P, S, and V supported");
  139.                 s = optionState;
  140.                 break;
  141.  
  142.             case optionState:
  143.                 if (p[k] != '\0') {
  144.                     if ((p[k] < '0' || p[k] > '9') && p[k] != '-' && p[k] != '+')
  145.                         PipeReportError(pipeFilteringErr, "\pA number must follow the option code");
  146.                     aNum[0] = 1;
  147.                     aNum[1] = p[k];
  148.                     s = numState;
  149.                     }
  150.                 break;
  151.  
  152.             case numState:
  153.                 if (p[k] == '\0') {
  154.                     StringToNum(aNum, &aLong);
  155.                     if (opt == 'V')
  156.                         voiceID = aLong;
  157.                     else if (opt == 'P')
  158.                         pitchIncr = aLong;
  159.                     else if (opt == 'S')
  160.                         speed = aLong;
  161.                     s = idleState;
  162.                     }
  163.                 else {
  164.                     if (aNum[0] >= 7 || p[k] < '0' || p[k] > '9')
  165.                         PipeReportError(pipeFilteringErr, "\pBad parameter");
  166.                     aNum[0]++;
  167.                     aNum[aNum[0]] = p[k];
  168.                     }
  169.                     break;
  170.  
  171.             default:
  172.                 PipeReportError(pipeFilteringErr, "\pBad character in parameter");
  173.             }
  174.         }
  175.  
  176.     //
  177.     //    initialise the speech manager
  178.     //
  179.  
  180.     // check whether the user requires a particular voice
  181.     if (voiceID == 0) {
  182.  
  183.         // No particular voice is requested. Check how many voices are available.
  184.         err = CountVoices(&voiceCount);
  185.         if (err != noErr) PipeReportError(pipeFilteringErr, "\pNo voices available");
  186.  
  187.         // grab the first voice which can be successfully identified
  188.         err = pipeFilteringErr;
  189.         for (k = 1; k <= voiceCount  &&  err != noErr; k++)
  190.             err = GetIndVoice(k, &voice);
  191.         if (err != noErr) PipeReportError(pipeFilteringErr, "\pNo voices actually available");
  192.         }
  193.     else {
  194.  
  195.         // the user requests a particular voice
  196.         err = GetIndVoice(voiceID, &voice);
  197.         if (err != noErr) PipeReportError(pipeFilteringErr, "\pRequested voice not available");
  198.         }
  199.  
  200.     // open a new channel (it will be disposed of when the application quits)
  201.     err = NewSpeechChannel(&voice, &chan);
  202.     if (err != noErr) PipeReportError(pipeFilteringErr, "\pNo speech channel available");
  203.  
  204.     // check whether we have to update the speech rate
  205.     if (speed != 0) {
  206.         err = GetSpeechRate(chan, &rate);
  207.         if (err != noErr) PipeReportError(pipeFilteringErr, "\pSpeech rate unobtainable");
  208.  
  209.         rate = (long)speed * 0x10000L;
  210.         err = SetSpeechRate(chan, rate);
  211.         if (err != noErr) PipeReportError(pipeFilteringErr, "\pSpeech rate cannot be set");
  212.         }
  213.  
  214.     // check whether we have to change the pitch
  215.     if (pitchIncr != 0) {
  216.         err = GetSpeechPitch(chan, &pitch);
  217.         if (err != noErr) PipeReportError(pipeFilteringErr, "\pPitch unobtainable");
  218.  
  219.         pitch += (long)pitchIncr * 0x60000L;
  220.         err = SetSpeechPitch(chan, pitch);
  221.         if (err != noErr) PipeReportError(pipeFilteringErr, "\pPitch cannot be set");
  222.         }
  223.  
  224. RETURN_LBL:
  225.     return (noErr);
  226.     } // HandleParameters
  227.